package cn.jhz.learn.blog.config.security;

import cn.jhz.learn.blog.component.shiro.PermissionName;
import cn.jhz.learn.blog.po.account.AccountPermission;
import cn.jhz.learn.blog.service.security.permission.PermissionService;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class PermissionPreProcessor implements ApplicationListener<ContextRefreshedEvent> {

    private final PermissionService permissionService;
    private final RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Autowired
    public PermissionPreProcessor(PermissionService permissionService, RequestMappingHandlerMapping requestMappingHandlerMapping) {
        this.permissionService = permissionService;
        this.requestMappingHandlerMapping = requestMappingHandlerMapping;
    }


    /**
     * 将系统中所有权限表达式加载进入数据库
     * 0:从数据库中查询出所有权限表达式，然后对比，如果已经存在了，跳过，不存在添加
     * 1:获取controller中所有带有@RequestMapper标签的方法
     * 2:遍历所有方法，判断当前方法是否贴有@RequiresPermissions权限控制标签
     * 3:如果有，解析得到权限表达式，封装成Permission对象保存到Permission表中,
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        AccountPermission permission;
        List<String> resourcesList = permissionService.getAllPermission();
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
        Collection<HandlerMethod> methods = handlerMethods.values();

        permissionService.addPermission(
                methods.stream()
                        .filter(method -> method.getMethodAnnotation(RequiresPermissions.class)!= null)
                        .filter(
                                method -> !resourcesList.contains(
                                        method.getMethodAnnotation(PermissionName.class).value()
                                )
                        )
                        .map(
                                method -> new AccountPermission(
                                        method.getMethodAnnotation(PermissionName.class).value(),
                                        method.getMethodAnnotation(RequiresPermissions.class).value()[0]
                                )
                        )
                        .collect(Collectors.toList())
        );
    }
}
